package org.metasketch.editor.links;

import java.util.Arrays;
import java.util.List;

public class SemanticLinkConfig implements ILinkConfig {

	boolean inherited = false;

	SemanticEndConfig source = new SemanticEndConfig();

	SemanticEndConfig target = new SemanticEndConfig();

	String script;

	public SemanticEndConfig getSource() {
		return source;
	}

	public SemanticEndConfig isSourceOrTarget(Class type) {
		if (type == null) {

			if (target.getTypes().size() == 0)
				return target;
			else if (target.getTypes().size() == 0)
				return target;
			else
				return null;
		}

		if (!inherited) {

			if (source.getTypes().contains(type))
				return source;

			else if (target.getTypes().contains(type))
				return target;

			return null;
		} else {

			for (Class iterType : source.getTypes()) {
				if (iterType.isAssignableFrom(type))
					return source;
			}

			for (Class iterType : target.getTypes()) {
				if (iterType.isAssignableFrom(type))
					return target;
			}

		}
		return null;
	}

	public EndType getStrictFinishEndType(Class startType, Class finishType) {

		if (startType != null && finishType != null) {
			if (!inherited) {

				if (source.getTypes().contains(startType)
						&& target.getTypes().contains(finishType))
					return EndType.TARGET;
				else
					return null;

			} else {

				boolean found = false;
				for (Class iterType : source.getTypes()) {
					if (iterType.isAssignableFrom(startType)) {
						found = true;
						break;
					}
				}

				if (!found)
					return null;

				for (Class iterType : target.getTypes()) {
					if (iterType.isAssignableFrom(finishType))
						return EndType.TARGET;
				}

				return null;

			}
		} else if (startType == null && finishType == null) {
			if (source.getTypes().size() == 0 && target.getTypes().size() == 0)
				return EndType.TARGET;
			else
				return null;
		} else if (startType == null && finishType != null) {
			if (!inherited) {
				if (source.getTypes().size() == 0
						&& target.getTypes().contains(finishType))
					return EndType.TARGET;
				else
					return null;
			} else {
				if (source.getTypes().size() > 0)
					return null;

				for (Class iterType : target.getTypes()) {
					if (iterType.isAssignableFrom(finishType))
						return EndType.TARGET;
				}

				return null;

			}
		} else if (startType != null && finishType == null) {
			if (!inherited) {
				if (source.getTypes().contains(startType)
						&& target.getTypes().size() == 0)
					return EndType.TARGET;
				else
					return null;
			} else {
				if (target.getTypes().size() > 0)
					return null;

				for (Class iterType : source.getTypes()) {
					if (iterType.isAssignableFrom(startType))
						return EndType.TARGET;
				}

				return null;
			}
		}
		return null;

	}

	public EndType getFinishEndType(Class startType, Class finishType) {

		if (startType == null && finishType == null) {
			if (source.getTypes().size() == 0 && target.getTypes().size() == 0)
				return EndType.TARGET;
			else
				return null;
		} else if (startType == null && finishType != null) {
			if (!inherited) {

				if (source.getTypes().size() == 0
						&& target.getTypes().contains(finishType))
					return EndType.TARGET;
				else if (target.getTypes().size() == 0
						&& source.getTypes().contains(finishType))
					return EndType.SOURCE;
				else
					return null;

			} else {

				if (target.getTypes().size() == 0) {
					for (Class iterType : source.getTypes()) {
						if (iterType.isAssignableFrom(finishType))
							return EndType.SOURCE;
					}
					return null;
				} else if (source.getTypes().size() == 0) {

					for (Class iterType : target.getTypes()) {
						if (iterType.isAssignableFrom(finishType))
							return EndType.TARGET;
					}
					return null;
				}

			}

		} else if (startType != null && finishType == null) {

			if (!inherited) {

				if (source.getTypes().size() == 0
						&& target.getTypes().contains(startType))
					return EndType.TARGET;
				else if (target.getTypes().size() == 0
						&& source.getTypes().contains(startType))
					return EndType.SOURCE;
				else
					return null;

			} else {

				if (target.getTypes().size() == 0) {
					for (Class iterType : source.getTypes()) {
						if (iterType.isAssignableFrom(startType))
							return EndType.SOURCE;
					}
					return null;
				} else if (source.getTypes().size() == 0) {

					for (Class iterType : target.getTypes()) {
						if (iterType.isAssignableFrom(startType))
							return EndType.TARGET;
					}
					return null;
				}

			}

		} else {

			if (!inherited) {

				if (source.getTypes().contains(startType)) {

					if (target.getTypes().contains(finishType))
						return EndType.TARGET;
					else
						return null;

				} else if (target.getTypes().contains(startType)) {

					if (source.getTypes().contains(finishType))
						return EndType.SOURCE;
					else
						return null;
				}

			} else {

				boolean found = false;
				for (Class iterType : source.getTypes()) {
					if (iterType.isAssignableFrom(startType)) {
						found = true;
						break;
					}
				}

				if (found) {

					for (Class iterType : target.getTypes()) {
						if (iterType.isAssignableFrom(finishType))
							return EndType.TARGET;
					}

					return null;
				} else {

					for (Class iterType : source.getTypes()) {
						if (iterType.isAssignableFrom(finishType)) {
							found = true;
							break;
						}
					}

					if (!found)
						return null;

					for (Class iterType : target.getTypes()) {
						if (iterType.isAssignableFrom(startType))
							return EndType.SOURCE;
					}

				}

			}
		}

		return null;

	}

	public void setSource(SemanticEndConfig source) {
		this.source = source;
	}

	public SemanticEndConfig getTarget() {
		return target;
	}

	public void setTarget(SemanticEndConfig target) {
		this.target = target;
	}

	// source methods

	public void setSourceTypes(Class... types) {
		source.setTypes(Arrays.asList(types));
	}

	public void setSourceTypes(List<Class> types) {
		source.setTypes(types);
	}

	public void setSourceLinkEnd(LinkEnd linkEnd) {
		source.setLinkEnd(linkEnd);
	}

	public void setSourceFieldName(String fieldName) {
		source.setFieldName(fieldName);
	}

	public void setSourceSemanticFieldName(String fieldName) {
		source.setSemanticFieldName(fieldName);
	}

	// target methods

	public void setTargetTypes(Class... types) {
		target.setTypes(Arrays.asList(types));
	}

	public void setTargetTypes(List<Class> types) {
		target.setTypes(types);
	}

	public void setTargetLinkEnd(LinkEnd linkEnd) {
		target.setLinkEnd(linkEnd);
	}

	public void setTargetFieldName(String fieldName) {
		target.setFieldName(fieldName);
	}

	public void setTargetSemanticFieldName(String fieldName) {
		target.setSemanticFieldName(fieldName);
	}

	public String getScript() {
		return script;
	}

	public void setScript(String script) {
		this.script = script;
	}

	public boolean isInherited() {
		return inherited;
	}

	public void setInherited(boolean inherited) {
		this.inherited = inherited;
	}

}
